/**
 * @author Steve Sedlmayr
 * @mail ssedlmayr@gmail.com
 * @link http://code.google.com/p/chitin/
 * @version 0.1
 
	The MIT License

	Copyright (c) 2009 Steve Sedlmayr

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.
*/

package srs.chitin.mvstate.base
{
	import flash.display.Sprite;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	
	/** 
	 * A typed event for notification that a view's state has changed.
	 * 
	 * @eventType srs.chitin.mvstate.base.StateChangeEventBase.STATE_CHANGE_EVENT
	 */
	[Event(name="stateChangeEvent", type="StateChangeEventBase")]
	
	/** 
      * Base class for the View portion of the truncated MVC pattern.
      * A subclassable Singleton.
	  */
	public class ViewBase extends Sprite implements IView, IViewState {
		/**
		 * The Singleton instance of the ViewBase class.
		 */
		private static var _instance:ViewBase;
		
		/** 
		 * The context object for the State pattern. In a canonical State pattern, 
		 * the context object acts as a delegate for an object's states.
		 */
		protected var _context:ContextBase;
		
		/** 
		  * Returns the view object's context object.
		  * 
		  * @return Returns the context of the view object.
		  */
		public function get context() : IViewState {
			return _context;
		}
		
		/** 
		 * An object to store the models used by the view, if any.
		 */
		protected var _modelEnumeration:Object = new Object();
		
		/** 
		 * Returns an object containing all of the models used by the view.
		 * 
		 * @return A clone of this view's enumerated model object.
		 */
		public function get modelEnumeration() : Object {
			var clone:Object = new Object;
			
			for ( var property:String in this._modelEnumeration ) {
				clone[property] = this._modelEnumeration[property];
			}
			
			return clone;
		}
		
		/** 
		 * An object in which to store any child views.
		 */
		protected var _viewEnumeration:Object = new Object();
		
		/** 
		 * An enumeration of all of the view's child views.
		 * 
		 * @return Returns an object containing the view's child views.
		 */
		public function get viewEnumeration() : Object {
			var clone:Object = new Object;
			
			for ( var property:String in this._viewEnumeration ) {
				clone[property] = this._viewEnumeration[property];
			}
			
			return clone;
		}
		
		/**
		 * ViewBase class constructor. Calls <code>super()</code> on Sprite and initializes.
		 * Throws an error if a client class tries to instantiate the class directly.
		 * 
		 * @param enforcer Enforces the Singleton pattern by requiring a parameter of a type defined in, 
		 * and only visible to, instances of this class. Any other class attempting instantiation
		 * will meet with a type error. Each layer of hierarchy from ViewBase should have a corresponding
		 * enforcer class derived from ViewBaseEnforcer with the same degree of inheritance.
		 */
		public function ViewBase(enforcer:ViewBaseEnforcer=null) : void {
			if ( enforcer != null ) {
				super();
				initialize();
			} else {
				//TO-DO :: get the id param working
				throw new Error("PATTERN ERROR: YOU HAVE ATTEMPTED ILLEGAL INSTANTIATION OF A SINGLETON CLASS." + 
					"THIS CONSTRUCTOR REQUIRES A SUBCLASS OF ViewBaseEnforcer DEFINED AS A LOCAL GENERIC IN THE SINGLETON SUBCLASS." + 
					"PLEASE REFER TO YOUR PROJECT DOCUMENTATION AND CONTACT THE UI LEAD AND/OR AUTHOR OF THIS DOCUMENT.");
			}
		}
		
		/**
		 * Returns the Singleton instance for the ViewBase class. 
		 * 
		 * @return The Singleton instance for the ViewBase class.
		 */
		public static function getInstance() : ViewBase {
			if ( _instance == null ) {
				_instance = new ViewBase(new ViewBaseEnforcer());
				_instance._context = ContextBase.getInstance();
			}
			
			return _instance;
		}
		
		/** 
		 * Perform initialization here in concrete subclasses.
		 */
		public function initialize() : void {
			draw();
		}
		
		/** 
		 * Perform display-list-relevant tasks here in subclasses.
		 */
		public function draw() : void {}
		
		/** 
		 * Adds a model to this view.
		 * 
		 * @param model The model to add to the view object.
		 * 
		 * @param name The name with which the model will be enumerated in the view.
		 */
		public function addModel(model:ModelBase, name:String) : void {
			this._modelEnumeration[name] = model;
			model.addEventListener(OutboundEventBase.OUTBOUND_EVENT, outboundEventHandler, false, 0, true);
		}
		
		/** 
		 * Retrieve a model using its name as a key.
		 * 
		 * @param name The name of the model to retrieve from the view.
		 * 
		 * @return An instance of the model specified by the <code>name</code> parameter.
		 */
		public function getModel(name:String) : ModelBase {
			if ( this._modelEnumeration[name] ) {
				return this._modelEnumeration[name];
			} else {
				return null;
			}
		}
		
		/** 
		 * Adds a child view to this view.
		 * 
		 * @param view The child view to add to the current view.
		 * 
		 * @param name The name with which the child will be enumerated.
		 */
		public function addView(view:ViewBase, name:String) : void {
			this._viewEnumeration[name] = view;
			view.addEventListener(StateChangeEventBase.STATE_CHANGE_EVENT, stateChangeEventHandler, false, 0, true);
		}
		
		/** 
		 * Retrieve a child view by its name.
		 * 
		 * @param name The name of the child view to retrieve.
		 * 
		 * @return An instance of the child specified by the name.
		 * 
		 */
		public function getView(name:String) : ViewBase {
			if ( this._viewEnumeration[name] ) {
				return this._viewEnumeration[name];
			} else {
				return null;
			}
		}
		
		/** 
		 * Hides the view. The specific implementation is up to the concrete implementing class.
		 * Hiding could mean setting visible to false, setting alpha to 0 or some other value,
		 * or performing an animation, for instance. This method implements the IViewState interface
		 * used by ViewStateBase but is not to be confused with the State pattern. It can be used as a
		 * pass-through to wrap the State pattern <code>hide()</code> method call if that is desired, 
		 * but is more likely to be used by a parent to control the entire view.
		 * 
		 * @param targetView The view to target the hide operation on in the concrete subclass instance.
		 * Usually the current view.
		 * 
		 * @param targetState (OPTIONAL) A state, most likely the next state to be shown, on which to
		 * perform operations associated with hiding the current view. 
		 */
		public function hide(targetView:ViewBase, targetState:String=null) : void {}
		
		/** 
		 * Shows the view. The specific implementation is up to the concrete implementing class.
		 * Showing could entail setting visibility or simply enacting a behavior. Not to be confused
		 * with the implementation for the State pattern, which employs IViewState via the context.
		 * 
		 * @param targetView The view to target the show operation on in the concrete subclass instance; 
		 * mostly likely the current view.
		 */
		public function show(targetView:ViewBase) : void {}
		
		/**
		 * Handle outbound events from a model or models. The specific implementation is up to the concrete implementing class.
		 * 
		 * @param event An outbound event to fire out to a listener.
		 */
		protected function outboundEventHandler(event:OutboundEventBase) : void {}
		
		/** 
		 * Handle state change events from a view or views. The specific implementation is up to the concrete implementing class.
		 * 
		 * @param event A state change event firing from a child view.
		 */
		protected function stateChangeEventHandler(event:StateChangeEventBase) : void {}
	}
}